import { createNextTickOnce, defaultShouldUpdate } from '@/utils';
import PubSub from '@/utils/PubSub';
import voidRender from '@/utils/voidRender';
import React, { createRef, useEffect, useImperativeHandle, useState } from 'react';
import useWillMountEffect from './useWillMountEffect';

/**
 * 创建一个共享的钩子
 * 钩子的参数会被忽略，因为参数无法共享
 * 钩子中无法获得当前的Context
 * @param {Function} factoryHook                              被共享的钩子
 * @param {any} initialValue                                  初始值
 * @param {function(a: any, b: any): boolean} shouldUpdate    判断是否需要更新
 * @param {Boolean} standalone                                不卸载
 * @return {Function}
 */
function createSharedHook(
  factoryHook = () => null,
  initialValue = null,
  shouldUpdate = defaultShouldUpdate,
  standalone = false,
) {
  const pubsub = new PubSub(shouldUpdate);
  pubsub.value = initialValue;
  const providerRef = createRef();
  providerRef.current = false;
  const shouldRender = () => (pubsub.listeners.length > 0 || standalone) && !providerRef.current;
  const shouldUnmount = () => pubsub.listeners.length === 0 && providerRef.current;

  function Comp() {
    const result = factoryHook();
    useImperativeHandle(providerRef, () => true, []);
    useWillMountEffect(() => {
      pubsub.update(result);
      return () => {
        pubsub.update(null);
      };
    });

    useEffect(() => {
      pubsub.update(result);
    }, [result]);

    return null;
  }

  let unmount;

  const nextTickRender = createNextTickOnce(() => {
    if (shouldRender()) {
      unmount = voidRender(<Comp />);
    } else if (shouldUnmount()) {
      unmount();
      unmount = null;
    }
  });

  nextTickRender();

  return useShared;

  function useShared() {
    const [state, setState] = useState(pubsub.value);

    nextTickRender();
    useWillMountEffect(pubsub.sub, setState);
    useEffect(() => nextTickRender, []);

    return state;
  }
}

export default createSharedHook;
